/**
 * Created by wangdasong
 */
/**
 *  istanbul ignore next
 */
import Vue from 'vue';

const isServer = true;//Vue.config.globalProperties.$isServer;
// const SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
const SPECIAL_CHARS_REGEXP = /((.))/g;
const MOZ_HACK_REGEXP = /^moz([A-Z])/;
const ieVersion = isServer ? 0 : Number(document.documentMode);

const trim = function(string) {
    return (string || '').replace(/^[\s\uFEFF]+|[\s\uFEFF]+$/g, '');
};
const camelCase = function(name) {
    return name
        .replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
            return offset ? letter.toUpperCase() : letter;
        })
        .replace(MOZ_HACK_REGEXP, 'Moz$1');
};

export const on = (function() {
    if (!isServer && document.addEventListener) {
        return function(element, event, handler) {
            if (element && event && handler) {
                element.addEventListener(event, handler, false);
            }
        };
    } else {
        return function(element, event, handler) {
            if (element && event && handler) {
                element.attachEvent('on' + event, handler);
            }
        };
    }
})();

export const off = (function() {
    if (!isServer && document.removeEventListener) {
        return function(element, event, handler) {
            if (element && event) {
                element.removeEventListener(event, handler, false);
            }
        };
    } else {
        return function(element, event, handler) {
            if (element && event) {
                element.detachEvent('on' + event, handler);
            }
        };
    }
})();

export const once = function(el, event, fn) {
    let listener = function() {
        if (fn) {
            fn.apply(this, arguments);
        }
        off(el, event, listener);
    };
    on(el, event, listener);
};

export function hasClass(el, cls) {
    if (!el || !cls) return false;
    if (cls.indexOf(' ') !== -1) throw new Error('className should not contain space.');
    if (el.classList) {
        return el.classList.contains(cls);
    } else {
        return (' ' + el.className + ' ').indexOf(' ' + cls + ' ') > -1;
    }
}

export function addClass(el, cls) {
    if (!el) return;
    let curClass = el.className,
        classes = (cls || '').split(' ');

    for (let i = 0, j = classes.length; i < j; i++) {
        let clsName = classes[i];
        if (!clsName) continue;

        if (el.classList) {
            el.classList.add(clsName);
        } else {
            if (!hasClass(el, clsName)) {
                curClass += ' ' + clsName;
            }
        }
    }
    if (!el.classList) {
        el.className = curClass;
    }
}

export function removeClass(el, cls) {
    if (!el || !cls) return;
    let classes = cls.split(' '),
        curClass = ' ' + el.className + ' ';

    for (let i = 0, j = classes.length; i < j; i++) {
        let clsName = classes[i];
        if (!clsName) continue;

        if (el.classList) {
            el.classList.remove(clsName);
        } else {
            if (hasClass(el, clsName)) {
                curClass = curClass.replace(' ' + clsName + ' ', ' ');
            }
        }
    }
    if (!el.classList) {
        el.className = trim(curClass);
    }
}

export const getStyle =
    ieVersion < 9
        ? function(element, styleName) {
              if (isServer) return;
              if (!element || !styleName) return null;
              styleName = camelCase(styleName);
              if (styleName === 'float') {
                  styleName = 'styleFloat';
              }
              try {
                  switch (styleName) {
                      case 'opacity':
                          try {
                              return element.filters.item('alpha').opacity / 100;
                          } catch (e) {
                              return 1.0;
                          }
                      default:
                          return element.style[styleName] || element.currentStyle
                              ? element.currentStyle[styleName]
                              : null;
                  }
              } catch (e) {
                  return element.style[styleName];
              }
          }
        : function(element, styleName) {
              if (isServer) return;
              if (!element || !styleName) return null;
              styleName = camelCase(styleName);
              if (styleName === 'float') {
                  styleName = 'cssFloat';
              }
              try {
                  let computed = document.defaultView.getComputedStyle(element, '');
                  return element.style[styleName] || computed ? computed[styleName] : null;
              } catch (e) {
                  return element.style[styleName];
              }
          };

export function setStyle(element, styleName, value) {
    if (!element || !styleName) return;

    if (typeof styleName === 'object') {
        for (let prop in styleName) {
            if (styleName.hasOwnProperty(prop)) {
                setStyle(element, prop, styleName[prop]);
            }
        }
    } else {
        styleName = camelCase(styleName);
        if (styleName === 'opacity' && ieVersion < 9) {
            element.style.filter = isNaN(value) ? '' : 'alpha(opacity=' + value * 100 + ')';
        } else {
            element.style[styleName] = value;
        }
    }
}

export function isAttached(element) {
    let currentNode = element.parentNode;
    while (currentNode) {
        if (currentNode.tagName === 'HTML') {
            return true;
        }
        if (currentNode.nodeType === 11) {
            return false;
        }
        currentNode = currentNode.parentNode;
    }
    return false;
}

let getComputedStyle = isServer ? {} : document.defaultView.getComputedStyle;

export function getScrollEventTarget(element) {
    let currentNode = element;
    // bugfix, see http://w3help.org/zh-cn/causes/SD9013 and http://stackoverflow.com/questions/17016740/onscroll-function-is-not-working-for-chrome
    while (
        currentNode &&
        currentNode.tagName !== 'HTML' &&
        currentNode.tagName !== 'BODY' &&
        currentNode.nodeType === 1
    ) {
        let overflowY = getComputedStyle(currentNode).overflowY;
        // console.log('!!!dom ===>>> ', currentNode.className, overflowY);
        if (overflowY === 'scroll' || overflowY === 'auto') {
            return currentNode;
        }
        currentNode = currentNode.parentNode;
    }
    return window;
}

/**
 * Detecting prefixes for saving time and bytes
 */
export function getDetectPrefixes() {
    let transform;
    let transition;
    let transitionEnd;
    let hasTranslate3d;
    (function() {
        let el = document.createElement('_');
        let style = el.style;
        let prop;
        if (style[(prop = 'webkitTransition')] === '') {
            transitionEnd = 'webkitTransitionEnd';
            transition = prop;
        }
        if (style[(prop = 'transition')] === '') {
            transitionEnd = 'transitionend';
            transition = prop;
        }
        if (style[(prop = 'webkitTransform')] === '') {
            transform = prop;
        }
        if (style[(prop = 'msTransform')] === '') {
            transform = prop;
        }
        if (style[(prop = 'transform')] === '') {
            transform = prop;
        }
        document.body.insertBefore(el, null);
        style[transform] = 'translate3d(0, 0, 0)';
        hasTranslate3d = !!global.getComputedStyle(el).getPropertyValue(transform);
        document.body.removeChild(el);
    })();
    return {
        transform,
        transition,
        transitionEnd,
        hasTranslate3d
    };
}

export function showElement(element, keepPointerEvents, delay) {
    if (!element) return;
    // force layout engine to compute elements current state
    getComputedStyle(element).opacity;

    let d = (delay || 300) + 'ms';

    if (!keepPointerEvents) element.style.pointerEvents = 'auto';
    element.style.transition = 'visibility 0ms, opacity ' + d;
    element.style.visibility = 'visible';
    element.style.opacity = '1';
}

export function hideElement(element, keepPointerEvents, delay) {
    let d = (delay || 300) + 'ms';

    if (!keepPointerEvents) element.style.pointerEvents = 'none';
    element.style.transition = 'visibility ' + d + ', opacity ' + d;
    element.style.visibility = 'hidden';
    element.style.opacity = '0';
}

export function hideAndRemoveElement(element, delay) {
    if (typeof element.removeTimer !== 'undefined') return;
    element.removeTimer = setTimeout(function() {
        element.parentNode.removeChild(element);
    }, delay || 300);
    hideElement(element, delay);
}

export function removeChildren(element) {
    if (!element) return;
    while (element.firstChild) element.removeChild(element.firstChild);
}

export function findNodeInParents(el, nodeName) { //eslint-disable-line
    let c = el.parentNode;
    while (c) {
        if (c.tagName === nodeName) return c;
        if (c.nodeType === 11) return null;
        c = c.parentNode;
    }
    return null;
}
